package container

import "fmt"

/**
 	切片
	切片本身没有值， 是对底层array的一个view(视图)
	所有的切片都是在原arr数组的范围中进行切出数据的！
	但是只能向后扩展，不能像前扩展！

	切片里面，声明的 var a []int 没有赋值上默认值， 默认是 nil，但是为nil的情况下，也可以直接往里面添加元素！

 */

/**
	切片是引用传递， 会直接修改原有的值
 */

// 修改其中的某个值
func updateSlice(s []int){
	s[0] = 100
}


func main() {

	arr := [...]int{0,1,2,3,4,5,6,7,8,9}

	// arr[2:6] =  [2 3 4 5]
	fmt.Println("arr[2:6] = ", arr[2:6])

	// arr[:6] =  [0 1 2 3 4 5]
	fmt.Println("arr[:6] = ", arr[:6])

	// arr[2:] =  [2 3 4 5 6 7 8 9]
	fmt.Println("arr[2:] = ", arr[2:])

	// arr[:] =  [0 1 2 3 4 5 6 7 8 9]
	fmt.Println("arr[:] = ", arr[:])


	/**
		通过 s1 := arr[2:6] 声明的切片  这个例子的结论：

		（1）s1 := arr[2:6] 想当于就是在原有的 arr 数组基础上，进行的一个部分内存地址的引用的指向，然后声明出的 s1 的这个变量！
		修改了 s1 里面的值，也会对原有的 arr 数组产生修改，因为他们使用的都是相同内存地址！

		（2）数组里面的每一个值在内存里面都会有一个唯一的内存地址标记！

	 */


	// 自动类型，获取一个数组的部分值，转换为切片
	s1 := arr[2:6]
	updateSlice(s1)
	// s1 =  [100 1 2 3 4 5 6 7 8 9]
	fmt.Println("s1 = ", s1)
	fmt.Println("arr = ", arr)

	/**
	    此时 s1 里面并没有 6~8 之间的下坐标数， 所以按照常理来说是没有值的！
		但是此时却是有值: s2 =  [8 9]，
		为什么会有值？

		推论：
			（1）这 s2 =  [8 9] 的值是原arr数组的值。
			（2）这 s2 =  [8 9] 的值，是我Go语言获取到 s1 的最后一个值之后，针对最后一个值进行的加1操作！
				也就是说 s1 切片里面最后一个值是 5，那么我Go语言获取到这个 5 之后，在这个值上面往后加1，然后5的后面是6！
		（1）正确
		（2）错误

		这两个论证点哪一个是真？

		但是继续测试  s2 =  [8 9] // 报错 ， 结果报错了，说切片超出范围！
		由此得知：我 s2 还是针对原arr数组获取的值！也就是说我的切片，切出的值都是基于原arr数组的范围！
		所以第一个论证点是正确的！

		所有的切片都是在原arr数组的范围中进行切出数据的！

		如果说 s1 := arr[2:6] 是这个范围，那么 s2 在s1上切片，s2 := s1[1:3] 是要出错的！因为s2受限于s1，
		但是 s2 := arr[6:8] 是受限于 原arr数组！
		也就是说 只能向后扩展，不能向前扩展！



	 */
	s2 := s1[6:8]
	// s2 =  [8 9] // 报错
	fmt.Println("s2 = ", s2)

	// s1=[100 3 4 5],len(s1)=4, cap(s1)=8
	/**
		cap 表示总共有多少个可看的容量, 相当于就是从起始位置算起，只能看后面的，不能看前面的！
		也就是说 s1 是从下坐标2开始的，就只能从2开始算起，有多少个可以看的元素！
	  */
	fmt.Printf("s1=%v,len(s1)=%d, cap(s1)=%d\n",s1,len(s1),cap(s1))


	/**
		切片添加元素的时候，是基于原arr元素的，
		如果超出了原arr数组的长度，Go语言会复制一份，在重新创建一个新的数组，新的数组的长度会比原arr数组要大,
		但是新数组的元素如果是旧数组的，那么就会继续使用原数组的元素的内存地址
		如果没有超出原arr数组，就把最后面的值给替换掉，那么对原arr数组本身存在数据会产生影响也会进行修改，因为内存地址相同
	 */

	s3 := arr[4:9]
	fmt.Println("s3 = ", s3)
	// 往slice切片里面添加一个 元素
	s4 := append(s3, 23)
	fmt.Println("s4 = ", s4)
	fmt.Println("arr = ", arr)

	// make 分配函数
	/**
		make() 只用于映射、切片和程道，不返回指针。要明确的得到指针用 new() 分配
		make在分配的时候，不能超过总共大小的元素空间！
		比如 make([]int, 5, 10) 在分配的时候，第二个参数的不能大于第三个参数的值！
	 */
	//创建一个初始元素个数为5的数组切片，元素初始值为0，并预留10个元素的存储空间
	// 相当于就是初始化5个大小的数组切片，然后共10个空间位置
	makeA := make([]int, 5, 10)    // len(makeA)=5, cap(makeA)=10
	fmt.Println("makeA = ", makeA)

	// 复制值，把 s1 的值复制到 makeA 中
	copy(makeA, s1)
	fmt.Println("复制之后的makeA = ", makeA)

	// 删除操作
	// 复制之后的makeA =  [100 3 4 5 0]
	// 删除makeA中的第3个元素，下坐标也就是2
	makeA = append(makeA[:2], makeA[3:]...)
	fmt.Println("删除元素后的 makeA = ", makeA) // [100 3 5 0]

}
